package org.zjx.window.operation;


import org.zjx.window.window.IWindow;

import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 操作执行器基础实现
 * 提供鼠标、键盘、截图等基本操作的默认实现，图像识别方法需要子类实现
 *
 * @author zjx
 * @since 1.0
 */
public abstract class BaseOperationExecutor implements OperationExecutor {

    /**
     * 关联的窗口实例
     */
    protected IWindow window;

    /**
     * AWT Robot实例，用于执行底层输入操作
     */
    protected final Robot robot;

    //鼠标当前坐标
    protected Point mousePosition = new Point(0, 0);

    /**
     * 默认构造方法
     * 创建Robot实例并初始化默认设置
     *
     * @throws RuntimeException 如果创建 Robot实例失败
     */
    public BaseOperationExecutor() {
        try {
            this.robot = new Robot();
            this.robot.setAutoDelay(10); // 设置自动延迟为10ms
        } catch (AWTException e) {
            throw new RuntimeException("创建 Robot 实例失败", e);
        }
    }

    /**
     * 带窗口参数的构造方法
     *
     * @param window 关联的窗口实例
     * @throws IllegalArgumentException 如果window为 null
     */
    public BaseOperationExecutor(IWindow window) {
        this();
        setWindow(Objects.requireNonNull(window, "窗口实例不能为 null"));
    }

    @Override
    public IWindow getWindow() {
        return window;
    }

    @Override
    public void setWindow(IWindow window) {
        this.window = window;
    }

    @Override
    public Robot getRobot() {
        return robot;
    }

    // ========== 鼠标操作实现 ==========

    @Override
    public void move(int x, int y) {
        mousePosition = new Point(x, y);
        robot.mouseMove(x, y);
    }

    @Override
    public void gameMove(int x, int y) {
        Rectangle bounds = window.getTrueBounds();
        int screenX = bounds.x + x;
        int screenY = bounds.y + y;
        robot.mouseMove(screenX, screenY);
    }

    @Override
    public void gameMove(Rectangle rectangle) {
        Objects.requireNonNull(rectangle, "移动区域不能为 null");

        Rectangle bounds = window.getTrueBounds();
        int randomX = rectangle.x + ThreadLocalRandom.current().nextInt(rectangle.width);
        int randomY = rectangle.y + ThreadLocalRandom.current().nextInt(rectangle.height);
        int screenX = bounds.x + randomX;
        int screenY = bounds.y + randomY;
        robot.mouseMove(screenX, screenY);
    }

    @Override
    public void click(int x, int y) {
        move(x, y);
        delay(50);
        click(1); // 默认左键点击
    }

    @Override
    public void click(int button) {
        validateMouseButton(button);
        pressMouse(button);
        delay(30);
        releaseMouse(button) ;
    }

    @Override
    public void pressMouse(int button) {
        validateMouseButton(button);
        robot.mousePress(getMouseButtonMask(button));
    }

    @Override
    public void releaseMouse(int button) {
        validateMouseButton(button);
        robot.mouseRelease(getMouseButtonMask(button));
    }

    @Override
    public Point getMousePosition() {
        return MouseInfo.getPointerInfo().getLocation();
    }

    @Override
    public void drag(int fromX, int fromY, int toX, int toY) {
        move(fromX, fromY);
        delay(50);
        pressMouse(1); // 左键按下
        delay(100);
        move(toX, toY);
        delay(50);
        releaseMouse(1); // 左键释放
    }

    // ========== 键盘操作实现 ==========

    @Override
    public void press(int keyCode) {
        robot.keyPress(keyCode);
        delay(30);
        robot.keyRelease(keyCode);
    }

    @Override
    public void pressKey(int keyCode) {
        robot.keyPress(keyCode);
    }

    @Override
    public void releaseKey(int keyCode) {
        robot.keyRelease(keyCode);
    }

    @Override
    public void input(String text) {
        Objects.requireNonNull(text, "输入文本不能为 null");

        for (char c : text.toCharArray()) {
            int keyCode = getKeyCode(c);
            if (keyCode != 0) {
                press(keyCode);
                delay(20);
            }
        }
    }

    @Override
    public void hotkey(int... keyCodes) {
        if (keyCodes == null || keyCodes.length == 0) {
            throw new IllegalArgumentException("快捷键键码序列不能为空");
        }

        // 按下所有键
        for (int keyCode : keyCodes) {
            robot.keyPress(keyCode);
        }

        delay(50);

        // 释放所有键
        for (int keyCode : keyCodes) {
            robot.keyRelease(keyCode);
        }
    }

    // ========== 截图操作实现 ==========

    @Override
    public BufferedImage screenshot() {
        validateWindowState();
        Rectangle bounds = window.getBounds();
        return robot.createScreenCapture(bounds);
    }

    @Override
    public BufferedImage screenshot(Rectangle region) {
        Objects.requireNonNull(region, "截图区域不能为 null");
        validateWindowState();

        Rectangle bounds = window.getTrueBounds();
        Rectangle screenRegion = new Rectangle(
                bounds.x + region.x,
                bounds.y + region.y,
                region.width,
                region.height
        );
        return robot.createScreenCapture(screenRegion);
    }

    // ========== 工具方法 ==========

    @Override
    public void delay(long milliseconds) {
        if (milliseconds < 0) {
            throw new IllegalArgumentException("延迟时间不能为负数: " + milliseconds);
        }

        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            // 不抛出异常，允许中断延迟
        }
    }

    // ========== 保护的工具方法 ==========

    /**
     * 验证窗口状态是否可用
     *
     * @throws IllegalStateException 如果窗口不可用
     */
    protected void validateWindowState() {
        if (window == null) {
            throw new IllegalStateException("操作执行器未关联窗口");
        }
        if (!window.isExists()) {
            throw new IllegalStateException("关联的窗口不存在");
        }
        if (!window.isValid()) {
            throw new IllegalStateException("关联的窗口无效");
        }
    }

    /**
     * 验证鼠标按钮参数是否有效
     *
     * @param button 鼠标按钮代码
     * @throws IllegalArgumentException 如果按钮代码无效
     */
    protected void validateMouseButton(int button) {
        if (button < 1 || button > 3) {
            throw new IllegalArgumentException("无效的鼠标按钮: " + button + "，有效值为1(左键),2(中键),3(右键)");
        }
    }

    /**
     * 将窗口相对坐标转换为屏幕绝对坐标
     *
     * @param x 窗口相对X坐标
     * @param y 窗口相对Y坐标
     * @return 屏幕绝对坐标
     */
    protected Point toScreenCoordinates(int x, int y) {
        validateWindowState();
        Rectangle bounds = window.getTrueBounds();
        return new Point(bounds.x + x, bounds.y + y);
    }

    /**
     * 将窗口相对区域转换为屏幕绝对区域
     *
     * @param region 窗口相对区域
     * @return 屏幕绝对区域
     */
    protected Rectangle toScreenRegion(Rectangle region) {
        validateWindowState();
        Rectangle bounds = window.getTrueBounds();
        return new Rectangle(
                bounds.x + region.x,
                bounds.y + region.y,
                region.width,
                region.height
        );
    }

    // ========== 私有工具方法 ==========

    /**
     * 获取鼠标按钮的AWT掩码
     *
     * @param button 鼠标按钮：1-左键, 2-中键, 3-右键
     * @return 对应的AWT按钮掩码
     */
    private int getMouseButtonMask(int button) {
        switch (button) {
            case 1:
                return InputEvent.BUTTON1_DOWN_MASK;
            case 2:
                return InputEvent.BUTTON2_DOWN_MASK;
            case 3:
                return InputEvent.BUTTON3_DOWN_MASK;
            default:
                return InputEvent.BUTTON1_DOWN_MASK; // 默认左键
        }
    }

    /**
     * 将字符转换为对应的键码
     * 注意：此方法只处理基本字符，复杂字符需要扩展
     *
     * @param c 要转换的字符
     * @return 对应的键码，如果无法转换返回0
     */
    private int getKeyCode(char c) {
        // 大写字母
        if (c >= 'A' && c <= 'Z') {
            return KeyEvent.VK_A + (c - 'A');
        }
        // 小写字母
        if (c >= 'a' && c <= 'z') {
            return KeyEvent.VK_A + (c - 'a');
        }
        // 数字
        if (c >= '0' && c <= '9') {
            return KeyEvent.VK_0 + (c - '0');
        }
        // 特殊字符
        switch (c) {
            case ' ':
                return KeyEvent.VK_SPACE;
            case '\n':
                return KeyEvent.VK_ENTER;
            case '\t':
                return KeyEvent.VK_TAB;
            case '.':
                return KeyEvent.VK_PERIOD;
            case ',':
                return KeyEvent.VK_COMMA;
            case ';':
                return KeyEvent.VK_SEMICOLON;
            case ':':
                return KeyEvent.VK_COLON;
            case '!':
                return KeyEvent.VK_EXCLAMATION_MARK;
            default:
                return 0; // 无法处理的字符
        }
    }
}